home *** CD-ROM | disk | FTP | other *** search
- //------------------------------------------------------------------------------
- // File: StillCapDlg.cpp
- //
- // Desc: DirectShow sample code - implementation of callback and dialog
- // objects for StillCap application.
- //
- // Copyright (c) 1999-2001 Microsoft Corporation. All rights reserved.
- //------------------------------------------------------------------------------
-
-
- #include "stdafx.h"
- #include "StillCap.h"
- #include "StillCapDlg.h"
- #include "..\..\common\dshowutil.cpp"
-
- #ifdef _DEBUG
- #define new DEBUG_NEW
- #undef THIS_FILE
- static char THIS_FILE[] = __FILE__;
- #endif
-
- // An application can advertise the existence of its filter graph
- // by registering the graph with a global Running Object Table (ROT).
- // The GraphEdit application can detect and remotely view the running
- // filter graph, allowing you to 'spy' on the graph with GraphEdit.
- //
- // To enable registration in this sample, define REGISTER_FILTERGRAPH.
- //
- #ifdef DEBUG
- #define REGISTER_FILTERGRAPH
- #endif
-
- // Constants
- #define WM_CAPTURE_BITMAP WM_APP + 1
-
- // Global data
- BOOL g_bOneShot = FALSE;
- DWORD g_dwGraphRegister=0; // For running object table
- HWND g_hwnd;
-
- // Structures
- typedef struct _callbackinfo
- {
- double dblSampleTime;
- long lBufferSize;
- BYTE *pBuffer;
- BITMAPINFOHEADER bih;
-
- } CALLBACKINFO;
-
- CALLBACKINFO cb={0};
-
-
- // Note: this object is a SEMI-COM object, and can only be created statically.
- // We use this little semi-com object to handle the sample-grab-callback,
- // since the callback must provide a COM interface. We could have had an interface
- // where you provided a function-call callback, but that's really messy, so we
- // did it this way. You can put anything you want into this C++ object, even
- // a pointer to a CDialog. Be aware of multi-thread issues though.
- //
- class CSampleGrabberCB : public ISampleGrabberCB
- {
- public:
- // these will get set by the main thread below. We need to
- // know this in order to write out the bmp
- long lWidth;
- long lHeight;
- CStillCapDlg * pOwner;
- TCHAR m_szCapDir[MAX_PATH]; // the directory we want to capture to
- TCHAR m_szSnappedName[MAX_PATH];
- BOOL bFileWritten;
-
- CSampleGrabberCB( )
- {
- pOwner = NULL;
- m_szCapDir[0] = 0;
- bFileWritten = FALSE;
- }
-
- // fake out any COM ref counting
- //
- STDMETHODIMP_(ULONG) AddRef() { return 2; }
- STDMETHODIMP_(ULONG) Release() { return 1; }
-
- // fake out any COM QI'ing
- //
- STDMETHODIMP QueryInterface(REFIID riid, void ** ppv)
- {
- if( riid == IID_ISampleGrabberCB || riid == IID_IUnknown )
- {
- *ppv = (void *) static_cast<ISampleGrabberCB*> ( this );
- return NOERROR;
- }
- return E_NOINTERFACE;
- }
-
- // we don't implement this interface for this example
- //
- STDMETHODIMP SampleCB( double SampleTime, IMediaSample * pSample )
- {
- return 0;
- }
-
- // The sample grabber is calling us back on its deliver thread.
- // This is NOT the main app thread!
- //
- // !!!!! WARNING WARNING WARNING !!!!!
- //
- // On Windows 9x systems, you are not allowed to call most of the
- // Windows API functions in this callback. Why not? Because the
- // video renderer might hold the global Win16 lock so that the video
- // surface can be locked while you copy its data. This is not an
- // issue on Windows 2000, but is a limitation on Win95,98,98SE, and ME.
- // Calling a 16-bit legacy function could lock the system, because
- // it would wait forever for the Win16 lock, which would be forever
- // held by the video renderer.
- //
- // As a workaround, copy the bitmap data during the callback,
- // post a message to our app, and write the data later.
- //
- STDMETHODIMP BufferCB( double dblSampleTime, BYTE * pBuffer, long lBufferSize )
- {
- // this flag will get set to true in order to take a picture
- //
- if( !g_bOneShot )
- return 0;
-
- // Since we can't access Windows API functions in this callback, just
- // copy the bitmap data to a global structure for later reference.
- cb.dblSampleTime = dblSampleTime;
- cb.lBufferSize = lBufferSize;
-
- // If we haven't yet allocated the data buffer, do it now.
- // Just allocate what we need to store the new bitmap.
- if (!cb.pBuffer)
- cb.pBuffer = new BYTE[lBufferSize];
-
- // Copy the bitmap data into our global buffer
- if (cb.pBuffer)
- memcpy(cb.pBuffer, pBuffer, lBufferSize);
-
- // Post a message to our application, telling it to come back
- // and write the saved data to a bitmap file on the user's disk.
- PostMessage(g_hwnd, WM_CAPTURE_BITMAP, 0, 0L);
- return 0;
- }
-
- // This function will be called whenever a captured still needs to be
- // displayed in the preview window. It is called initially within
- // CopyBitmap() to display the captured still, but it is also called
- // whenever the main dialog needs to repaint and when we transition
- // from video capture mode back into still capture mode.
- //
- BOOL DisplayCapturedBits(BYTE *pBuffer, BITMAPINFOHEADER *pbih)
- {
- // If we haven't yet snapped a still, return
- if (!bFileWritten || !pOwner || !pBuffer)
- return FALSE;
-
- // put bits into the preview window with StretchDIBits
- //
- HWND hwndStill = NULL;
- pOwner->GetDlgItem( IDC_STILL, &hwndStill );
-
- RECT rc;
- ::GetWindowRect( hwndStill, &rc );
- long lStillWidth = rc.right - rc.left;
- long lStillHeight = rc.bottom - rc.top;
-
- HDC hdcStill = GetDC( hwndStill );
- PAINTSTRUCT ps;
- BeginPaint(hwndStill, &ps);
-
- SetStretchBltMode(hdcStill, COLORONCOLOR);
- StretchDIBits(
- hdcStill, 0, 0,
- lStillWidth, lStillHeight,
- 0, 0, lWidth, lHeight,
- pBuffer,
- (BITMAPINFO*) pbih,
- DIB_RGB_COLORS,
- SRCCOPY );
-
- EndPaint(hwndStill, &ps);
- ReleaseDC( hwndStill, hdcStill );
-
- return TRUE;
- }
-
- // This is the implementation function that writes the captured video
- // data onto a bitmap on the user's disk.
- //
- BOOL CopyBitmap( double dblSampleTime, BYTE * pBuffer, long lBufferSize )
- {
- if( !g_bOneShot )
- return 0;
-
- // we only take one at a time
- //
- g_bOneShot = FALSE;
-
- // figure out where to capture to
- //
- TCHAR m_ShortName[MAX_PATH];
- wsprintf( m_szSnappedName, TEXT("%sStillCap%4.4ld.bmp"),
- m_szCapDir, pOwner->m_nCapTimes );
- wsprintf( m_ShortName, TEXT("StillCap%4.4ld.bmp"),
- pOwner->m_nCapTimes );
-
- // increment bitmap number if user requested it
- // otherwise, we'll reuse the filename next time
- if( pOwner->IsDlgButtonChecked( IDC_AUTOBUMP ) )
- pOwner->m_nCapTimes++;
-
- // write out a BMP file
- //
- HANDLE hf = CreateFile(
- m_szSnappedName, GENERIC_WRITE, 0, NULL,
- CREATE_ALWAYS, NULL, NULL );
-
- if( hf == INVALID_HANDLE_VALUE )
- return 0;
-
- // write out the file header
- //
- BITMAPFILEHEADER bfh;
- memset( &bfh, 0, sizeof( bfh ) );
- bfh.bfType = 'MB';
- bfh.bfSize = sizeof( bfh ) + lBufferSize + sizeof( BITMAPINFOHEADER );
- bfh.bfOffBits = sizeof( BITMAPINFOHEADER ) + sizeof( BITMAPFILEHEADER );
-
- DWORD dwWritten = 0;
- WriteFile( hf, &bfh, sizeof( bfh ), &dwWritten, NULL );
-
- // and the bitmap format
- //
- BITMAPINFOHEADER bih;
- memset( &bih, 0, sizeof( bih ) );
- bih.biSize = sizeof( bih );
- bih.biWidth = lWidth;
- bih.biHeight = lHeight;
- bih.biPlanes = 1;
- bih.biBitCount = 24;
-
- dwWritten = 0;
- WriteFile( hf, &bih, sizeof( bih ), &dwWritten, NULL );
-
- // and the bits themselves
- //
- dwWritten = 0;
- WriteFile( hf, pBuffer, lBufferSize, &dwWritten, NULL );
- CloseHandle( hf );
- bFileWritten = TRUE;
-
- // Display the bitmap bits on the dialog's preview window
- DisplayCapturedBits(pBuffer, &bih);
-
- // Save bitmap header for later use when repainting the window
- memcpy(&(cb.bih), &bih, sizeof(bih));
-
- // show where it captured
- //
- pOwner->SetDlgItemText( IDC_SNAPNAME, m_ShortName );
-
- // Enable the 'View Still' button
- HWND hwndButton = NULL;
- pOwner->GetDlgItem( IDC_BUTTON_VIEWSTILL, &hwndButton );
- ::EnableWindow(hwndButton, TRUE);
-
- // play a snap sound
- if (pOwner->IsDlgButtonChecked(IDC_PLAYSOUND))
- {
- TCHAR szSound[128];
- GetWindowsDirectory(szSound, 128);
- _tcscat(szSound, TEXT("\\media\\click.wav\0"));
- sndPlaySound(szSound, SND_ASYNC);
- }
-
- return 0;
- }
-
- };
-
- // this semi-COM object will receive sample callbacks for us
- //
- CSampleGrabberCB mCB;
-
- /////////////////////////////////////////////////////////////////////////////
- // CAboutDlg dialog used for App About
-
- class CAboutDlg : public CDialog
- {
- public:
- CAboutDlg();
-
- // Dialog Data
- //{{AFX_DATA(CAboutDlg)
- enum { IDD = IDD_ABOUTBOX };
- //}}AFX_DATA
-
- // ClassWizard generated virtual function overrides
- //{{AFX_VIRTUAL(CAboutDlg)
- protected:
- virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
- //}}AFX_VIRTUAL
-
- // Implementation
- protected:
- //{{AFX_MSG(CAboutDlg)
- //}}AFX_MSG
- DECLARE_MESSAGE_MAP()
- };
-
- CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
- {
- //{{AFX_DATA_INIT(CAboutDlg)
- //}}AFX_DATA_INIT
- }
-
- void CAboutDlg::DoDataExchange(CDataExchange* pDX)
- {
- CDialog::DoDataExchange(pDX);
- //{{AFX_DATA_MAP(CAboutDlg)
- //}}AFX_DATA_MAP
- }
-
- BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
- //{{AFX_MSG_MAP(CAboutDlg)
- // No message handlers
- //}}AFX_MSG_MAP
- END_MESSAGE_MAP()
-
- /////////////////////////////////////////////////////////////////////////////
- // CStillCapDlg dialog
-
- CStillCapDlg::CStillCapDlg(CWnd* pParent /*=NULL*/)
- : CDialog(CStillCapDlg::IDD, pParent)
- {
- //{{AFX_DATA_INIT(CStillCapDlg)
- // NOTE: the ClassWizard will add member initialization here
- //}}AFX_DATA_INIT
- // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
- m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
- }
-
- void CStillCapDlg::DoDataExchange(CDataExchange* pDX)
- {
- CDialog::DoDataExchange(pDX);
- //{{AFX_DATA_MAP(CStillCapDlg)
- DDX_Control(pDX, IDC_STATUS, m_StrStatus);
- DDX_Control(pDX, IDC_STILL, m_StillScreen);
- DDX_Control(pDX, IDC_PREVIEW, m_PreviewScreen);
- //}}AFX_DATA_MAP
- }
-
- BEGIN_MESSAGE_MAP(CStillCapDlg, CDialog)
- //{{AFX_MSG_MAP(CStillCapDlg)
- ON_WM_PAINT()
- ON_WM_SYSCOMMAND()
- ON_WM_QUERYDRAGICON()
- ON_BN_CLICKED(IDC_SNAP, OnSnap)
- ON_BN_CLICKED(IDC_CAPSTILLS, OnCapstills)
- ON_BN_CLICKED(IDC_CAPVID, OnCapvid)
- ON_BN_CLICKED(IDC_BUTTON_RESET, OnButtonReset)
- ON_BN_CLICKED(IDC_BUTTON_VIEWSTILL, OnButtonViewstill)
- ON_WM_CLOSE()
- //}}AFX_MSG_MAP
- END_MESSAGE_MAP()
-
- /////////////////////////////////////////////////////////////////////////////
- // CStillCapDlg message handlers
-
- void CStillCapDlg::OnSysCommand(UINT nID, LPARAM lParam)
- {
- if ((nID & 0xFFF0) == IDM_ABOUTBOX)
- {
- CAboutDlg dlgAbout;
- dlgAbout.DoModal();
- }
- else
- {
- CDialog::OnSysCommand(nID, lParam);
- }
- }
-
-
- // If you add a minimize button to your dialog, you will need the code below
- // to draw the icon. For MFC applications using the document/view model,
- // this is automatically done for you by the framework.
- void CStillCapDlg::OnPaint()
- {
- if (IsIconic())
- {
- CPaintDC dc(this); // device context for painting
-
- SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
-
- // Center icon in client rectangle
- int cxIcon = GetSystemMetrics(SM_CXICON);
- int cyIcon = GetSystemMetrics(SM_CYICON);
- CRect rect;
- GetClientRect(&rect);
- int x = (rect.Width() - cxIcon + 1) / 2;
- int y = (rect.Height() - cyIcon + 1) / 2;
-
- // Draw the icon
- dc.DrawIcon(x, y, m_hIcon);
- }
- else
- {
- CDialog::OnPaint();
-
- // Update the bitmap preview window, if we have
- // already captured bitmap data
- mCB.DisplayCapturedBits(cb.pBuffer, &(cb.bih));
- }
- }
-
- // The system calls this to obtain the cursor to display while the user drags
- // the minimized window.
- HCURSOR CStillCapDlg::OnQueryDragIcon()
- {
- return (HCURSOR) m_hIcon;
- }
-
- BOOL CStillCapDlg::OnInitDialog()
- {
- CDialog::OnInitDialog();
-
- // Add "About..." menu item to system menu.
-
- // IDM_ABOUTBOX must be in the system command range.
- ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
- ASSERT(IDM_ABOUTBOX < 0xF000);
-
- CMenu* pSysMenu = GetSystemMenu(FALSE);
- if (pSysMenu != NULL)
- {
- CString strAboutMenu;
- strAboutMenu.LoadString(IDS_ABOUTBOX);
- if (!strAboutMenu.IsEmpty())
- {
- pSysMenu->AppendMenu(MF_SEPARATOR);
- pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
- }
- }
-
- // Set the icon for this dialog. The framework does this automatically
- // when the application's main window is not a dialog
- SetIcon(m_hIcon, TRUE); // Set big icon
- SetIcon(m_hIcon, FALSE); // Set small icon
-
- // StillCap-specific initialization
- CoInitialize( NULL );
-
- // default to this capture directory
- //
- SetDlgItemText( IDC_CAPDIR, TEXT("c:\\") );
-
- // default to capturing stills
- //
- CheckDlgButton( IDC_CAPSTILLS, 1 );
- m_bCapStills = true;
- m_nCapState = 0;
- m_nCapTimes = 0;
- g_hwnd = GetSafeHwnd();
-
- // start up the still image capture graph
- //
- HRESULT hr = InitStillGraph( );
- if (FAILED(hr))
- Error( TEXT("Failed to initialize StillGraph!"));
-
- // Modify the window style of the capture and still windows
- // to prevent excessive repainting
- m_PreviewScreen.ModifyStyle(0, WS_CLIPCHILDREN);
- m_StillScreen.ModifyStyle(0, WS_CLIPCHILDREN);
-
- return TRUE; // return TRUE unless you set the focus to a control
- }
-
- void CStillCapDlg::ClearGraphs( )
- {
- // Destroy capture graph
- if( m_pGraph )
- {
- // have to wait for the graphs to stop first
- //
- CComQIPtr< IMediaControl, &IID_IMediaControl > pControl = m_pGraph;
- if( pControl )
- pControl->Stop( );
-
- // make the window go away before we release graph
- // or we'll leak memory/resources
- //
- CComQIPtr< IVideoWindow, &IID_IVideoWindow > pWindow = m_pGraph;
- if( pWindow )
- {
- pWindow->put_Visible( OAFALSE );
- pWindow->put_Owner( NULL );
- }
-
- #ifdef REGISTER_FILTERGRAPH
- // Remove filter graph from the running object table
- if (g_dwGraphRegister)
- RemoveGraphFromRot(g_dwGraphRegister);
- #endif
-
- m_pGraph.Release( );
- m_pGrabber.Release( );
- }
-
- // Destroy playback graph, if it exists
- if( m_pPlayGraph )
- {
- CComQIPtr< IMediaControl, &IID_IMediaControl > pControl = m_pPlayGraph;
- if( pControl )
- pControl->Stop( );
-
- CComQIPtr< IVideoWindow, &IID_IVideoWindow > pWindow = m_pPlayGraph;
- if( pWindow )
- {
- pWindow->put_Visible( OAFALSE );
- pWindow->put_Owner( NULL );
- }
-
- m_pPlayGraph.Release( );
- }
- }
-
- HRESULT CStillCapDlg::InitStillGraph( )
- {
- HRESULT hr;
-
- // create a filter graph
- //
- hr = m_pGraph.CoCreateInstance( CLSID_FilterGraph );
- if( !m_pGraph )
- {
- Error( TEXT("Could not create filter graph") );
- return E_FAIL;
- }
-
- // get whatever capture device exists
- //
- CComPtr< IBaseFilter > pCap;
- GetDefaultCapDevice( &pCap );
- if( !pCap )
- {
- Error( TEXT("No video capture device was detected on your system.\r\n\r\n")
- TEXT("This sample requires a functional video capture device, such\r\n")
- TEXT("as a USB web camera.") );
- return E_FAIL;
- }
-
- // add the capture filter to the graph
- //
- hr = m_pGraph->AddFilter( pCap, L"Cap" );
- if( FAILED( hr ) )
- {
- Error( TEXT("Could not put capture device in graph"));
- return E_FAIL;
- }
-
- // create a sample grabber
- //
- hr = m_pGrabber.CoCreateInstance( CLSID_SampleGrabber );
- if( !m_pGrabber )
- {
- Error( TEXT("Could not create SampleGrabber (is qedit.dll registered?)"));
- return hr;
- }
- CComQIPtr< IBaseFilter, &IID_IBaseFilter > pGrabBase( m_pGrabber );
-
- // force it to connect to video, 24 bit
- //
- CMediaType VideoType;
- VideoType.SetType( &MEDIATYPE_Video );
- VideoType.SetSubtype( &MEDIASUBTYPE_RGB24 );
- hr = m_pGrabber->SetMediaType( &VideoType ); // shouldn't fail
- if( FAILED( hr ) )
- {
- Error( TEXT("Could not set media type"));
- return hr;
- }
-
- // add the grabber to the graph
- //
- hr = m_pGraph->AddFilter( pGrabBase, L"Grabber" );
- if( FAILED( hr ) )
- {
- Error( TEXT("Could not put sample grabber in graph"));
- return hr;
- }
-
- // find the two pins and connect them
- //
- IPin * pCapOut = GetOutPin( pCap, 0 );
- IPin * pGrabIn = GetInPin( pGrabBase, 0 );
- hr = m_pGraph->Connect( pCapOut, pGrabIn );
- if( FAILED( hr ) )
- {
- Error( TEXT("Could not connect capture pin #0 to grabber.\r\n")
- TEXT("Is the capture device being used by another application?"));
- return hr;
- }
-
- // render the sample grabber output pin, so we get a preview window
- //
- IPin * pGrabOut = GetOutPin( pGrabBase, 0 );
- hr = m_pGraph->Render( pGrabOut );
- if( FAILED( hr ) )
- {
- Error( TEXT("Could not render sample grabber output pin"));
- return hr;
- }
-
- // ask for the connection media type so we know how big
- // it is, so we can write out bitmaps
- //
- AM_MEDIA_TYPE mt;
- hr = m_pGrabber->GetConnectedMediaType( &mt );
- if ( FAILED( hr) )
- {
- Error( TEXT("Could not read the connected media type"));
- return hr;
- }
-
- VIDEOINFOHEADER * vih = (VIDEOINFOHEADER*) mt.pbFormat;
- mCB.pOwner = this;
- mCB.lWidth = vih->bmiHeader.biWidth;
- mCB.lHeight = vih->bmiHeader.biHeight;
- FreeMediaType( mt );
-
- // don't buffer the samples as they pass through
- //
- m_pGrabber->SetBufferSamples( FALSE );
-
- // only grab one at a time, stop stream after
- // grabbing one sample
- //
- m_pGrabber->SetOneShot( FALSE );
-
- // set the callback, so we can grab the one sample
- //
- m_pGrabber->SetCallback( &mCB, 1 );
-
- // find the video window and stuff it in our window
- //
- CComQIPtr< IVideoWindow, &IID_IVideoWindow > pWindow = m_pGraph;
- if( !pWindow )
- {
- Error( TEXT("Could not get video window interface"));
- return E_FAIL;
- }
-
- // set up the preview window to be in our dialog
- // instead of floating popup
- //
- HWND hwndPreview = NULL;
- GetDlgItem( IDC_PREVIEW, &hwndPreview );
- RECT rc;
- ::GetWindowRect( hwndPreview, &rc );
- pWindow->put_Owner( (OAHWND) hwndPreview );
- pWindow->put_Left( 0 );
- pWindow->put_Top( 0 );
- pWindow->put_Width( rc.right - rc.left );
- pWindow->put_Height( rc.bottom - rc.top );
- pWindow->put_Visible( OATRUE );
- pWindow->put_WindowStyle( WS_CHILD | WS_CLIPSIBLINGS );
-
- // Add our graph to the running object table, which will allow
- // the GraphEdit application to "spy" on our graph
- #ifdef REGISTER_FILTERGRAPH
- hr = AddGraphToRot(m_pGraph, &g_dwGraphRegister);
- if (FAILED(hr))
- {
- Error(TEXT("Failed to register filter graph with ROT!"));
- g_dwGraphRegister = 0;
- }
- #endif
-
- // run the graph
- //
- CComQIPtr< IMediaControl, &IID_IMediaControl > pControl = m_pGraph;
- hr = pControl->Run( );
- if( FAILED( hr ) )
- {
- Error( TEXT("Could not run graph"));
- return hr;
- }
-
- UpdateStatus(_T("Previewing Live Video"));
- return 0;
- }
-
- HRESULT CStillCapDlg::InitCaptureGraph( TCHAR * pFilename )
- {
- HRESULT hr;
-
- // make a filter graph
- //
- m_pGraph.CoCreateInstance( CLSID_FilterGraph );
- if( !m_pGraph )
- {
- Error(TEXT("Could not create filter graph"));
- return E_FAIL;
- }
-
- // get whatever capture device exists
- //
- CComPtr< IBaseFilter > pCap;
- GetDefaultCapDevice( &pCap );
- if( !pCap )
- {
- Error( TEXT("No video capture device was detected on your system.\r\n\r\n")
- TEXT("This sample requires a functional video capture device, such\r\n")
- TEXT("as a USB web camera.") );
- return E_FAIL;
- }
-
- // add the capture filter to the graph
- //
- hr = m_pGraph->AddFilter( pCap, L"Cap" );
- if( FAILED( hr ) )
- {
- Error( TEXT("Could not put capture device in graph"));
- return hr;
- }
-
- // make a capture builder graph (for connecting help)
- //
- CComPtr< ICaptureGraphBuilder2 > pBuilder;
- hr = pBuilder.CoCreateInstance( CLSID_CaptureGraphBuilder2 );
- if( !pBuilder )
- {
- Error( TEXT("Could not create capture graph builder2"));
- return hr;
- }
-
- hr = pBuilder->SetFiltergraph( m_pGraph );
- if( FAILED( hr ) )
- {
- Error( TEXT("Could not set filtergraph on graphbuilder2"));
- return hr;
- }
-
- CComPtr< IBaseFilter > pMux;
- CComPtr< IFileSinkFilter > pSink;
- USES_CONVERSION;
-
- hr = pBuilder->SetOutputFileName( &MEDIASUBTYPE_Avi,
- T2W( pFilename ),
- &pMux,
- &pSink );
- if( FAILED( hr ) )
- {
- Error( TEXT("Could not create/hookup mux and writer"));
- return hr;
- }
-
- hr = pBuilder->RenderStream( &PIN_CATEGORY_CAPTURE,
- &MEDIATYPE_Video,
- pCap,
- NULL,
- pMux );
- if( FAILED( hr ) )
- {
- Error( TEXT("Could not connect capture pin"));
- return hr;
- }
-
- hr = pBuilder->RenderStream( &PIN_CATEGORY_PREVIEW,
- &MEDIATYPE_Video,
- pCap,
- NULL,
- NULL );
- if( FAILED( hr ) )
- {
- Error( TEXT("Could not render capture pin"));
- return hr;
- }
- if( hr == VFW_S_NOPREVIEWPIN )
- {
- // preview was faked up using the capture pin, so we can't
- // turn capture on and off at will.
- hr = 0;
- }
-
- // find the video window and stuff it in our window
- //
- CComQIPtr< IVideoWindow, &IID_IVideoWindow > pWindow = m_pGraph;
- if( !pWindow )
- {
- Error( TEXT("Could not get video window interface"));
- return hr;
- }
-
- // set up the preview window to be in our dialog
- // instead of floating popup
- //
- HWND hwndPreview = NULL;
- GetDlgItem( IDC_PREVIEW, &hwndPreview );
- RECT rc;
- ::GetWindowRect( hwndPreview, &rc );
- pWindow->put_Owner( (OAHWND) hwndPreview );
- pWindow->put_Left( 0 );
- pWindow->put_Top( 0 );
- pWindow->put_Width( rc.right - rc.left );
- pWindow->put_Height( rc.bottom - rc.top );
- pWindow->put_Visible( OATRUE );
- pWindow->put_WindowStyle( WS_CHILD | WS_CLIPSIBLINGS );
-
- // run the graph
- //
- CComQIPtr< IMediaControl, &IID_IMediaControl > pControl = m_pGraph;
- hr = pControl->Run( );
- if( FAILED( hr ) )
- {
- Error( TEXT("Could not run graph"));
- return hr;
- }
-
- UpdateStatus(_T("Capturing Video To Disk"));
- return 0;
- }
-
- HRESULT CStillCapDlg::InitPlaybackGraph( TCHAR * pFilename )
- {
- m_pPlayGraph.CoCreateInstance( CLSID_FilterGraph );
- USES_CONVERSION;
-
- HRESULT hr = m_pPlayGraph->RenderFile( T2W( pFilename ), NULL );
- if (FAILED(hr))
- return hr;
-
- // find the video window and stuff it in our window
- //
- CComQIPtr< IVideoWindow, &IID_IVideoWindow > pWindow = m_pPlayGraph;
- if( !pWindow )
- {
- Error( TEXT("Could not get video window interface"));
- return E_FAIL;
- }
-
- // set up the preview window to be in our dialog
- // instead of floating popup
- //
- HWND hwndPreview = NULL;
- GetDlgItem( IDC_STILL, &hwndPreview );
- RECT rc;
- ::GetWindowRect( hwndPreview, &rc );
- pWindow->put_Owner( (OAHWND) hwndPreview );
- pWindow->put_Left( 0 );
- pWindow->put_Top( 0 );
- pWindow->put_Width( rc.right - rc.left );
- pWindow->put_Height( rc.bottom - rc.top );
- pWindow->put_Visible( OATRUE );
- pWindow->put_WindowStyle( WS_CHILD | WS_CLIPSIBLINGS );
-
- CComQIPtr< IMediaControl, &IID_IMediaControl > pControl;
- pControl = m_pPlayGraph;
-
- // Play back the recorded video
- pControl->Run( );
- UpdateStatus(_T("Playing Back Recorded Video"));
- return 0;
- }
-
- void CStillCapDlg::GetDefaultCapDevice( IBaseFilter ** ppCap )
- {
- HRESULT hr;
-
- *ppCap = NULL;
-
- // create an enumerator
- //
- CComPtr< ICreateDevEnum > pCreateDevEnum;
- pCreateDevEnum.CoCreateInstance( CLSID_SystemDeviceEnum );
- if( !pCreateDevEnum )
- return;
-
- // enumerate video capture devices
- //
- CComPtr< IEnumMoniker > pEm;
- pCreateDevEnum->CreateClassEnumerator( CLSID_VideoInputDeviceCategory, &pEm, 0 );
- if( !pEm )
- return;
-
- pEm->Reset( );
-
- // go through and find first video capture device
- //
- while( 1 )
- {
- ULONG ulFetched = 0;
- CComPtr< IMoniker > pM;
- hr = pEm->Next( 1, &pM, &ulFetched );
- if( hr != S_OK )
- break;
-
- // get the property bag interface from the moniker
- //
- CComPtr< IPropertyBag > pBag;
- hr = pM->BindToStorage( 0, 0, IID_IPropertyBag, (void**) &pBag );
- if( hr != S_OK )
- continue;
-
- // ask for the english-readable name
- //
- CComVariant var;
- var.vt = VT_BSTR;
- hr = pBag->Read( L"FriendlyName", &var, NULL );
- if( hr != S_OK )
- continue;
-
- // set it in our UI
- //
- USES_CONVERSION;
- SetDlgItemText( IDC_CAPOBJ, W2T( var.bstrVal ) );
-
- // ask for the actual filter
- //
- hr = pM->BindToObject( 0, 0, IID_IBaseFilter, (void**) ppCap );
- if( *ppCap )
- break;
- }
-
- return;
- }
-
- void CStillCapDlg::OnSnap()
- {
- CString CapDir;
- GetDlgItemText( IDC_CAPDIR, CapDir );
-
- // Snap a still picture?
- if( m_bCapStills )
- {
- _tcscpy( mCB.m_szCapDir, CapDir );
- g_bOneShot = TRUE;
- }
-
- // Start capturing video
- else
- {
- if( m_nCapState == 0 )
- {
- if( IsDlgButtonChecked( IDC_AUTOBUMP ) )
- m_nCapTimes++;
- }
-
- // Determine AVI filename
- TCHAR szFilename[MAX_PATH], szFile[MAX_PATH];
- wsprintf( szFilename, TEXT("%sStillCap%04d.avi"), CapDir, m_nCapTimes );
- wsprintf( szFile, TEXT("StillCap%04d.avi"), m_nCapTimes );
-
- // start capturing, show playing button
- //
- if( m_nCapState == 0 )
- {
- ClearGraphs( );
- InitCaptureGraph( szFilename );
- SetDlgItemText( IDC_SNAP, TEXT("&Start Playback"));
- m_nCapState = 1;
- }
- else if( m_nCapState == 1 )
- {
- // show us where it captured to
- //
- SetDlgItemText( IDC_SNAPNAME, szFile );
-
- ClearGraphs( );
- InitPlaybackGraph( szFilename );
- SetDlgItemText( IDC_SNAP, TEXT("&Start Capture"));
- m_nCapState = 0;
- }
- }
- }
-
- BOOL CStillCapDlg::DestroyWindow()
- {
- ClearGraphs( );
-
- return CDialog::DestroyWindow();
- }
-
- void CStillCapDlg::Error( TCHAR * pText )
- {
- GetDlgItem( IDC_SNAP )->EnableWindow( FALSE );
- ::MessageBox( NULL, pText, TEXT("Error!"), MB_OK | MB_TASKMODAL | MB_SETFOREGROUND );
- }
-
- void CStillCapDlg::OnCapstills()
- {
- if( m_bCapStills )
- return;
-
- SetDlgItemText( IDC_SNAP, TEXT("&Snap Still"));
- m_bCapStills = true;
-
- ClearGraphs( );
- InitStillGraph( );
-
- // Update the bitmap preview window, if we have
- // already captured bitmap data
- mCB.DisplayCapturedBits(cb.pBuffer, &(cb.bih));
- }
-
- void CStillCapDlg::OnCapvid()
- {
- if( !m_bCapStills )
- return;
-
- ClearGraphs( );
- m_bCapStills = false;
- m_nCapState = 0;
-
- // use OnSnap to set the UI state and the graphs
- //
- OnSnap( );
- }
-
- void CStillCapDlg::OnButtonReset()
- {
- // Reset bitmap counter to reset at zero
- m_nCapTimes = 0;
- }
-
- void CStillCapDlg::OnButtonViewstill()
- {
- // Open the bitmap with the system-default application
- ShellExecute(this->GetSafeHwnd(), TEXT("open\0"), mCB.m_szSnappedName,
- NULL, NULL, SW_SHOWNORMAL);
- }
-
- void CStillCapDlg::UpdateStatus(TCHAR *szStatus)
- {
- m_StrStatus.SetWindowText(szStatus);
- }
-
- LRESULT CStillCapDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
- {
- // Field the message posted by our SampleGrabber callback function.
- if (message == WM_CAPTURE_BITMAP)
- mCB.CopyBitmap(cb.dblSampleTime, cb.pBuffer, cb.lBufferSize);
-
- return CDialog::WindowProc(message, wParam, lParam);
- }
-
- void CStillCapDlg::OnClose()
- {
- // Free the memory allocated for our bitmap data buffer
- if (cb.pBuffer != 0)
- {
- delete cb.pBuffer;
- cb.pBuffer = 0;
- }
-
- CDialog::OnClose();
- }
-